package cn.flying.base.mybatis.interceptor;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.Objects;
import java.util.Properties;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import cn.flying.base.common.constants.Constants;
import cn.flying.base.common.utils.SnowflakeUtil;
import cn.flying.base.common.utils.ThreadLocalUtil;

/**
 * @description: mybatis拦截器设置修改人、修改时间，设置审计相关参数
 * @author: lvyong
 * @date: 2022年05月29日 16:50
 * @version: 1.0
 */
@Component
@Intercepts({@Signature(method = "update", type = Executor.class, args = {MappedStatement.class, Object.class})})
public class AuditInfoInterceptor implements Interceptor {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        fillField(invocation);
        return invocation.proceed();
    }

    private void fillField(Invocation invocation) {
        Object[] args = invocation.getArgs();
        SqlCommandType sqlCommandType = null;
        for (Object arg : args) {
            String className = arg.getClass().getName();
            logger.info("【{}】参数类型：【{}】", arg, className);
            //第一个参数处理。根据它判断是否给“操作属性”赋值。

            //如果是第一个参数 MappedStatement
            if (arg instanceof MappedStatement) {
                MappedStatement ms = (MappedStatement) arg;
                sqlCommandType = ms.getSqlCommandType();
                logger.info("操作类型：【{}】", sqlCommandType);
                if (sqlCommandType == SqlCommandType.INSERT || sqlCommandType == SqlCommandType.UPDATE) {
                    //如果是“增加”或“更新”操作，则继续进行默认操作信息赋值。否则，则退出
                    continue;
                } else {
                    break;
                }
            }

            Object username = ThreadLocalUtil.getThreadLocal().get(Constants.USER_NAME);
            if (sqlCommandType == SqlCommandType.INSERT) {
                for (Field f : arg.getClass().getDeclaredFields()) {
                    f.setAccessible(true);
                    switch (f.getName()) {
                        case "id":
                            if (!StringUtils.hasText(getProperty(arg, "id"))) {
                                setProperty(arg, "id", SnowflakeUtil.genId());
                            }
                            break;
                        case "createdBy":
                            if (Objects.nonNull(username)) {
                                setProperty(arg, "createdBy", username);
                            }
                            break;
                        case "createdTime":
                            setProperty(arg, "createdTime", new Date());
                            break;
                        case "updatedBy":
                            if (Objects.nonNull(username)) {
                                setProperty(arg, "updatedBy", username);
                            }
                            break;
                        case "updatedTime":
                            setProperty(arg, "updatedTime", new Date());
                            break;
//                        case "delFlag":
//                            setProperty(arg, "delFlag", "0");
//                            break;
                    }
                }
            } else if (sqlCommandType == SqlCommandType.UPDATE) {
                for (Field f : arg.getClass().getDeclaredFields()) {
                    f.setAccessible(true);
                    switch (f.getName()) {
                        case "updatedBy":
                            if (Objects.nonNull(username)) {
                                setProperty(arg, "updatedBy", username);
                            }
                            break;
                        case "updatedTime":
                            setProperty(arg, "updatedTime", new Date());
                            break;
                    }
                }
            }
        }
    }

    /**
     * 获取对象的属性赋值
     *
     * @param bean
     */
    private String getProperty(Object bean, String name) {
        try {
            //根据需要，将相关属性赋上默认值
            return BeanUtils.getProperty(bean, name);
        } catch (NoSuchMethodException e) {
            logger.warn("获取属性值失败", e.getMessage());
        } catch (InvocationTargetException e) {
            logger.warn("获取属性值失败", e.getMessage());
        } catch (IllegalAccessException e) {
            logger.warn("获取属性值失败", e.getMessage());
        }
        return null;
    }

    /**
     * 为对象的操作属性赋值
     *
     * @param bean
     */
    private void setProperty(Object bean, String name, Object value) {
        try {
            //根据需要，将相关属性赋上默认值
            BeanUtils.setProperty(bean, name, value);
        } catch (IllegalAccessException e) {
            logger.warn("赋值失败", e.getMessage());
        } catch (InvocationTargetException e) {
            logger.warn("赋值失败", e.getMessage());
        }
    }

    @Override
    public Object plugin(Object target) {
        return Interceptor.super.plugin(target);
    }

    @Override
    public void setProperties(Properties properties) {
        Interceptor.super.setProperties(properties);
    }
}
